﻿using System;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace PersonaLibrary.ViewModel.PrintViewModel.Model
{
	class DropPreviewAdorner : Adorner
	{
		#region Private Members
		/// <summary>
		/// child
		/// </summary>
		private readonly Rectangle _child;

		/// <summary>
		/// leftOffset
		/// </summary>
		private double _leftOffset;

		/// <summary>
		/// topOffset
		/// </summary>
		private double _topOffset;
		#endregion

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="DropPreviewAdorner"/> class.
		/// </summary>
		/// <param name="adornedElement">The adorned element.</param>
		/// <param name="adorningElement">The adorning element.</param>
		public DropPreviewAdorner(UIElement adornedElement, UIElement adorningElement)
			: base(adornedElement)
		{
			VisualBrush brush = new VisualBrush(adorningElement);
			_child = new Rectangle
			        	{
			        		Width = adorningElement.RenderSize.Width,
			        		Height = adorningElement.RenderSize.Height,
			        		Fill = brush,
			        		IsHitTestVisible = false
			        	};
			DoubleAnimation animation = new DoubleAnimation(0.3, 1, new Duration(TimeSpan.FromSeconds(1)))
			                            	{
			                            		AutoReverse = true,
			                            		RepeatBehavior = RepeatBehavior.Forever
			                            	};
			brush.BeginAnimation(Brush.OpacityProperty, animation);
		}
		#endregion

		#region Public Properties
		/// <summary>
		/// Gets or sets the left offset.
		/// </summary>
		/// <value>The left offset.</value>
		public double LeftOffset
		{
			get
			{
				return _leftOffset;
			}

			set
			{
				_leftOffset = value;
				UpdatePosition();
			}
		}

		/// <summary>
		/// Gets or sets the top offset.
		/// </summary>
		/// <value>The top offset.</value>
		public double TopOffset
		{
			get
			{
				return _topOffset;
			}

			set
			{
				_topOffset = value;
				UpdatePosition();
			}
		}
		#endregion

		#region Protected Properties
		/// <summary>
		/// Gets the number of visual child elements within this element.
		/// </summary>
		/// <value></value>
		/// <returns>Returns either zero (no child elements) or one (one child element).</returns>
		protected override int VisualChildrenCount
		{
			get
			{
				return 1;
			}
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Returns a <see cref="T:System.Windows.Media.Transform"></see> for the adorner, based on the transform that is currently applied to the adorned element.
		/// </summary>
		/// <param name="transform">The transform that is currently applied to the adorned element.</param>
		/// <returns>A transform to apply to the adorner.</returns>
		public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
		{
			GeneralTransformGroup result = new GeneralTransformGroup();
			result.Children.Add(base.GetDesiredTransform(transform));
			result.Children.Add(new TranslateTransform(LeftOffset, TopOffset));
			return result;
		}
		#endregion

		#region Protected Methods
		/// <summary>
		/// Implements any custom measuring behavior for the adorner.
		/// </summary>
		/// <param name="constraint">A size to constrain the adorner to.</param>
		/// <returns>
		/// A <see cref="T:System.Windows.Size"></see> object representing the amount of layout space needed by the adorner.
		/// </returns>
		protected override Size MeasureOverride(Size constraint)
		{
			_child.Measure(constraint);
			return _child.DesiredSize;
		}

		/// <summary>
		/// When implemented in a derived class, positions child elements and determines a size for a <see cref="T:System.Windows.FrameworkElement"></see>-derived class.
		/// </summary>
		/// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
		/// <returns>The actual size used.</returns>
		protected override Size ArrangeOverride(Size finalSize)
		{
			_child.Arrange(new Rect(finalSize));
			return finalSize;
		}

		/// <summary>
		/// Overrides <see cref="M:System.Windows.Media.Visual.GetVisualChild(System.Int32)"></see>, and returns a child at the specified index from that element's collection of child elements. However, in this override, the only valid index is zero.
		/// </summary>
		/// <param name="index">Zero-based index of the requested child element in the collection.</param>
		/// <returns>
		/// The requested child element. This should not return null; if the provided index is out of range, an exception should be raised.
		/// </returns>
		protected override Visual GetVisualChild(int index)
		{
			return _child;
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Updates the position.
		/// </summary>
		private void UpdatePosition()
		{
			AdornerLayer adornerLayer = Parent as AdornerLayer;
			if (adornerLayer != null)
			{
				adornerLayer.Update(AdornedElement);
			}
		}
		#endregion         
	}
}
